#include "StackupLayerParser.h"

#include "MatDesParser.h"
#include "DoubleParser.h"
#include "IdRefParser.h"
#include "QStringParser.h"

#include <QXmlStreamReader>
#include <QString>

namespace Ipc2581b
{

StackupLayerParser::StackupLayerParser(
    QStringParser *&_layerOrGroupRefParser
    , DoubleParser *&_thicknessParser
    , DoubleParser *&_tolPlusParser
    , DoubleParser *&_tolMinusParser
    , DoubleParser *&_sequenceParser
    , QStringParser *&_commentParser
    , MatDesParser *&_matDesParser
    , IdRefParser *&_specRefParser
):    m_layerOrGroupRefParser(_layerOrGroupRefParser)
    , m_thicknessParser(_thicknessParser)
    , m_tolPlusParser(_tolPlusParser)
    , m_tolMinusParser(_tolMinusParser)
    , m_sequenceParser(_sequenceParser)
    , m_commentParser(_commentParser)
    , m_matDesParser(_matDesParser)
    , m_specRefParser(_specRefParser)
{

}

bool StackupLayerParser::parse(QXmlStreamReader *reader)
{
    /* Pre */

    m_result.reset(new StackupLayer());

    /* Attributes */

    QStringRef data;
    if (reader->attributes().hasAttribute(QStringLiteral("layerOrGroupRef")))
    {
        data = reader->attributes().value(QStringLiteral("layerOrGroupRef"));
        if (!m_layerOrGroupRefParser->parse(reader, data))
            return false;
        m_result->layerOrGroupRef = m_layerOrGroupRefParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("layerOrGroupRef: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("thickness")))
    {
        data = reader->attributes().value(QStringLiteral("thickness"));
        if (!m_thicknessParser->parse(reader, data))
            return false;
        m_result->thickness = m_thicknessParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("thickness: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("tolPlus")))
    {
        data = reader->attributes().value(QStringLiteral("tolPlus"));
        if (!m_tolPlusParser->parse(reader, data))
            return false;
        m_result->tolPlus = m_tolPlusParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("tolPlus: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("tolMinus")))
    {
        data = reader->attributes().value(QStringLiteral("tolMinus"));
        if (!m_tolMinusParser->parse(reader, data))
            return false;
        m_result->tolMinus = m_tolMinusParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("tolMinus: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("sequence")))
    {
        data = reader->attributes().value(QStringLiteral("sequence"));
        if (!m_sequenceParser->parse(reader, data))
            return false;
        m_result->sequenceOptional = Optional<Double>(m_sequenceParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("comment")))
    {
        data = reader->attributes().value(QStringLiteral("comment"));
        if (!m_commentParser->parse(reader, data))
            return false;
        m_result->commentOptional = Optional<QString>(m_commentParser->result());
    }

    /* Elements */

    while (reader->readNextStartElement())
    {
        auto name = reader->name();
        if (name == QStringLiteral("MatDes"))
        {
            if (!m_matDesParser->parse(reader))
                return false;
            auto result = m_matDesParser->result();
            m_result->matDesOptional = Optional<MatDes*>(result);
        }
        else if (name == QStringLiteral("SpecRef"))
        {
            if (!m_specRefParser->parse(reader))
                return false;
            auto result = m_specRefParser->result();
            m_result->specRefList.append(result);
        }
        else
            reader->skipCurrentElement();
    }

    /* Post */

    // TODO: Check multiplicity of elements/attributes

    return true;
}

StackupLayer *StackupLayerParser::result()
{
    return m_result.take();
}

}